package code;

import java.util.HashMap;
import java.util.LinkedHashMap;

public class Controlador {
    HashMap<String, Grafo> listaGrafos = new LinkedHashMap<String, Grafo>();

    //Singleton
    private static Controlador instance = null;

    private Controlador(){
    }

    public static Controlador getInstance(){
        if (instance == null) {
            instance = new Controlador();
        }
        return instance;
    }

    public HashMap getListaGrafos() {
        return this.listaGrafos;    
    }

    public void setListaGrafos(HashMap<String, Grafo> map) {
        this.listaGrafos = map;
    }

    /**
     * Adiciona o grafo na lista
     * @param grafo
     * @throws Exception lança exceção caso já exista um grafo com este nome
     */
    public void addGrafo(Grafo grafo) throws Exception{
        if (listaGrafos.put(grafo.getNome(), grafo) != null){
            throw new Exception("Grafo já existe na lista");
        }
    }

    /**
     * Retorna o grafo
     * @param nome Contém o nome do grafo a ser retornado
     * @return retorna o grafo
     * @throws Exception lança exceção caso o grafo informado não exista
     */
    public Grafo getGrafo(String nome) throws Exception{
        Grafo grafo = listaGrafos.get(nome);
        if (grafo == null){
            throw new Exception("Grafo não existe na lista");
        }
        return grafo;
    }

    /**
     * Remove o grafo da lista
     * @param grafo
     * @throws Exception lança exceção caso o grafo informado não existir
     */
    public void removeGrafo(String nome) throws Exception{
        if (listaGrafos.remove(nome) == null){
            throw new Exception("Grafo não existe na lista");
        }
    }

    public void alteraNomeGrafo(String nomeAntigo, String nomeAtual) throws Exception{
        //verifica se o grafo está selecionado
        if (getGrafo(nomeAntigo) == null){
            throw new Exception("É necessário selecionar um grafo");
        }
        //verifica se o novo nome já está em uso
        if (listaGrafos.get(nomeAtual) != null){
            throw new Exception("O novo nome informado já está em uso");
        }
        
        Grafo grafo = listaGrafos.remove(nomeAntigo);  
        grafo.setNome(nomeAtual);
        listaGrafos.put(grafo.getNome(), grafo);
    }
    
    public void alteraNo(Grafo grafo, No noAntigo, No noNovo) throws Exception{
        No novo;
        //verifica se o grafo está selecionado
        if (getGrafo(grafo.getNome()) == null){
            throw new Exception("É necessário selecionar um grafo");
        }
        
        if (!grafo.existeNo(noAntigo.getNome())){
            throw new Exception("É necessário selecionar um nó");
        }
        
        //verifica se o novo nome já está em uso
        if (grafo.existeNo(noNovo.getNome())){
            throw new Exception("O novo nome informado já está em uso");
        }

        //Atualiza o nó antigo com base no nó novo. Dessa forma, não é perdida as referências com as arestas do nó alterado.
        novo = grafo.removeNo(noAntigo.getNome());
        novo.setNome(noNovo.getNome());
        novo.setCusto(noNovo.getCusto());
        novo.setEstado(noNovo.getEstado());
        grafo.addNo(novo);
    }

    public void alteraAresta(Grafo grafo, Aresta arestaAntiga, Aresta arestaNova) throws Exception{
        Aresta aresta;
        No noEsquerda;
        No noDireita;
        //verifica se o nome da aresta a ser trocado realmente existe
        aresta =  grafo.getAresta(arestaAntiga.getNome());
        if (aresta == null){
            throw new Exception("Aresta selecionada não existe");
        }

        //verifica se a aresta nova não existe
        aresta =  grafo.getAresta(arestaNova.getNome());
        if (aresta != null){
            throw new Exception("Nova aresta já existe");
        }

        //Remove aresta antiga
        noEsquerda = arestaAntiga.getNoEsquerda();
        noDireita = arestaAntiga.getNoDireita();
        noEsquerda.removeAresta(arestaAntiga.getNome());
        noDireita.removeAresta(arestaAntiga.getNome());

        //Adiciona aresta nova nos nós selecionados
        noEsquerda = arestaNova.getNoEsquerda();
        noDireita = arestaNova.getNoDireita();
        noEsquerda.addAresta(arestaNova);
        noDireita.addAresta(arestaNova);
    }    
}
